"use strict";

var Assert = (function(){

	var methods = {};

	String.prototype.format = function(params) {
		return this.replace(/{(\d+)}/gm , function(match , name){
			return params[~~name];
		});
	};

	methods.string = function(value , message) {
		if(typeof value !== "string") {
			throwError(message || "Expected a string. Got: {0}".format([value]));
		}
	};

	methods.stringNotEmpty = function(value , message) {
		this.string(value,message);
		this.notEmpty(value,message);
	};

	//验证整数
	methods.integer = function(value , message) {
		//fixme 000 / 001
		this.regex(value,/^-?\d+$/,message || "Expected an integer. Got: {0}".format([value]));
	};

	methods.numeric = function(value,message) {
		//fixme 00.1 / 00.00
		this.regex(value,/^-?\d+(\.\d+)?$/,message || "Expected a numeric. Got: {0}".format([value]));
	};

	methods.isEmpty = function(value , message) {
		if(!!value) {
			throwError(message || "Expected an empty value. Got: {0}".format([value]));
		}
	};

	methods.notEmpty = function(value , message) {
		if(!!!value) {
			throwError(message || "Expected a non-empty value. Got: {0}".format([value]));
		}
	};

	methods.notNull = function(value , message) {
		if(null === value) {
			throwError(message || "Expected a value other than null.");
		}
	};

	methods.eq = function(value1 , value2 , message) {
		if(value1 != value2) {
			throwError(message || "Expected a value equal to {0}. Got: {1}".format([value1 , value2]));
		}
	};

	methods.notEq = function(value1 , value2 , message) {
		if(value1 == value2) {
			throwError(message || "Expected a different value than {0}".format([value2]));
		}
	};

	methods.same = function(value1 , value2 , message) {
		if(value1 !== value2) {
			throwError(message || "Expected a value identical to {0}. Got: {1}".format([value1 , value2]));
		}
	};

	methods.notSame = function(value1 , value2 , message) {
			if(value1 === value2) {
				throwError(message || "Expected a value not identical to {0}".format([value2]));
			}
	};

	methods.gt = function(value1 , value2 , message) {
		if(value1 <= value2) {
			throwError(message || "Expected a value greater than {0}. Got: {1}".format([value1 , value2]));
		}
	};

	methods.egt = function(value1 , value2 , message) {
		if(value1 < value2) {
			throwError(message || "Expected a value greater than or equal to {0}. Got: {1}".format([value1 , value2]));
		}
	};

	methods.lt = function(value1 , value2 , message) {
		if(value1 >= value2) {
			throwError(message || "Expected a value less than {0}. Got: {1}".format([value1 , value2]));
		}
	};

	methods.elt = function(value1 , value2 , message) {
		if(value1 > value2) {
			throwError(message || "Expected a value less than or equal to {0}. Got: {1}".format([value1 , value2]));
		}
	};

	methods.range = function(value , min , max , message) {
		if(value < min || value > max) {
			throwError(message || "Expected a value between {0} and {1}. Got: {2}".format([min,max,value]));
		}
	};

	methods.oneOf = function(value , values , message) {
		if(!values.includes(value)) {
			throwError(message || "Expected one of: {0}. Got:{1}".format([value,values.join(',')]));
		}
	};

	methods.contains = function(value , query , message) {
		if(-1 == value.indexOf(query)) {
			throwError(message || "Expected a value to contain {0}. Got: {1}".format([value,query]));
		}
	};

	methods.startsWith = function(value , prefix , message) {
		if(!value.startsWith(prefix)) {
			throwError(message || "Expected a value to start with {0}. Got: {1}".format([value , prefix]));
		}
	};

	methods.endsWith = function(value , suffix , message) {
		if(!value.endsWith(suffix)) {
			throwError(message || "Expected a value to end with {0}. Got: {1}".format([value,suffix]));
		}
	};

	methods.length = function(value , length , message) {
		if(length !== value.length) {
			throwError(message || "Expected a value to contain {0} characters. Got: {1}".format([value,length]));
		}
	};

	methods.minLength = function(value , min , message) {
		if(value.length < min) {
			throwError(message || "Expected a value to contain at least {0} characters. Got:{1}".format(value , min));
		}
	};

	methods.maxLength = function(value , max , message) {
		if(value.length > max) {
			throwError(message || "Expected a value to contain at most {0} characters. Got: {1}".format([value , max]));
		}
	};

	methods.lengthBetween = function(value , min , max , message) {
		var length = value.length;
		if(length < min || length > max) {
			throwError(message || "Expected a value to contain between {0} and {1} characters. Got:{2}".format([min , max , value]));
		}
	};

	methods.count = function(array , number , message) {
		this.eq(array.length , number , message || "Expected an array to contain {0} elements. Got: {1}".format(number , array.length));
	};

	methods.uuid = function(value , message) {
		value = value.replace(/urn:|uuid:|\{|\}/,'');
		if ('00000000-0000-0000-0000-000000000000' === value) {
			return;
		}
		if(!/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/.test(value)) {
			throwError(message || "Value {0} is not a valid UUID.".format([value]));
		}
	};

	//验证正则
	methods.regex = function(value , rule , message) {
		if(!rule.test(value)) {
			throwError(message);
		}
	};


	function throwError(message) {
		throw new Error(message);
	}
	
	return methods;

})();